package com.gec.anan.dispatch.service.impl;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.gec.anan.common.constant.RedisConstant;
import com.gec.anan.common.result.Result;
import com.gec.anan.dispatch.mapper.OrderJobMapper;
import com.gec.anan.dispatch.service.NewOrderService;
import com.gec.anan.dispatch.xxl.client.XxlJobClient;
import com.gec.anan.map.client.LocationFeignClient;
import com.gec.anan.model.entity.dispatch.OrderJob;
import com.gec.anan.model.enums.OrderStatus;
import com.gec.anan.model.form.map.SearchNearByDriverForm;
import com.gec.anan.model.vo.dispatch.NewOrderTaskVo;
import com.gec.anan.model.vo.map.NearByDriverVo;
import com.gec.anan.model.vo.order.NewOrderDataVo;
import com.gec.anan.order.client.OrderInfoFeignClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {
    @Autowired
    private XxlJobClient xxlJobClient;
    @Autowired
    private OrderJobMapper orderJobMapper;

    @Autowired
    private LocationFeignClient locationFeignClient;

    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;

    @Autowired
    private RedisTemplate redisTemplate;

    //新建和开启定时任务
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        //查询乘客的下单是否开启了任务调度
        //根据订单id查询数据库
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getOrderId, newOrderTaskVo.getOrderId() );
        //返回的是订单的任务调度对象
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        System.out.println("orderJob:"+JSON.toJSONString(orderJob));
        System.out.println("进入到订单的任务调度中");
        //没开启任务调度则开启
        if (orderJob == null) {
            //参数
            //String executorHandler @Xxl注解的头部handler
            // String param 需要的参数
            // String corn  corn表达式(gui页面自动生成corn表达式)
            // String desc  相关的描述
            //返回的是jobId
            Long jobId = xxlJobClient.addAndStart("newOrderTaskHandler", "",
                    "0 0/1 * * * ?",

                    "开启定时任务"
            );
            System.out.println("开启定时任务");

            //拿到jobId后存入数据库的order_job表中
            orderJob = new OrderJob();
            orderJob.setJobId(jobId);
            orderJob.setOrderId(newOrderTaskVo.getOrderId());
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));
            orderJobMapper.insert(orderJob);
        }

        return orderJob.getJobId();
    }

    @Override
    public void executeTask(Long jobId) {
        //1.根据jobId查询orderjob是否存在，存在才继续执行
        System.out.println("进入到executeTask中");
        System.out.println("jobId为："+jobId);
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getJobId, jobId );
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        System.out.println("orderJob:"+JSON.toJSONString(orderJob));
        if(orderJob==null){
            return ;
        }
        System.out.println("executeTask-1");

        //2.查询订单的状态，乘客的订单被司机接走或者被乘客取消也不继续执行
        String jobParameter = orderJob.getParameter();
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(jobParameter, NewOrderTaskVo.class);
        Result<Integer> orderStatus = orderInfoFeignClient.getOrderStatus(newOrderTaskVo.getOrderId());
        //获取订单id
        Integer orderId = orderStatus.getData();
        //如果订单状态不是处在待接单的话，停止定时任务调度
        if(orderId!= OrderStatus.WAITING_ACCEPT.getStatus().intValue()){
            xxlJobClient.stopJob(jobId);
            //不是接单状态，司机不需要接单
            log.info("停止任务调度: {}", JSON.toJSONString(newOrderTaskVo));
            return ;
        }
        System.out.println("executeTask-2");

        //3.远程调用，查询乘客方圆5km的可接单司机
        //4.获取司机的集合
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());
        List<NearByDriverVo> nearByDriverVoList = locationFeignClient.searchNearByDriver(searchNearByDriverForm).getData();
        System.out.println("executeTask-3");

        //5.遍历集合，为每个司机创建临时队列，存储订单消息
        nearByDriverVoList.forEach(driver ->{
            //根据乘客的订单id生成key
            String repeatKey = RedisConstant.DRIVER_ORDER_REPEAT_LIST+newOrderTaskVo.getOrderId();

            Boolean isMember = redisTemplate.opsForSet().isMember(repeatKey, driver.getDriverId());
            //将乘客的订单推送到所有满足条件的多个司机（每个司机只会推送一次）
            System.out.println("isMember:"+isMember);
            if(!isMember){
                System.out.println("进入到这里来");
                redisTemplate.opsForSet().add(repeatKey, driver.getDriverId());
                //乘客订单超过15分钟自动取消
                redisTemplate.expire(repeatKey, 15, TimeUnit.MINUTES);
            }

            //乘客订单数据
            NewOrderDataVo newOrderDataVo = new NewOrderDataVo();
            BeanUtils.copyProperties(newOrderTaskVo, newOrderDataVo);
            newOrderDataVo.setDistance(driver.getDistance());
            System.out.println("newOrderDataVo:"+newOrderDataVo);

            //给司机创建临时队列，存放乘客订单数据，redis的list实现
            //key为司机的id
            System.out.println("driverId:"+driver.getDriverId());
            String key = RedisConstant.DRIVER_ORDER_TEMP_LIST+driver.getDriverId();

            redisTemplate.opsForList().leftPush(key,JSONObject.toJSONString(newOrderDataVo));
            //临时队列1分钟没抢单自动过期，再次获取新的订单消息
            redisTemplate.expire(key, RedisConstant.DRIVER_ORDER_TEMP_LIST_EXPIRES_TIME, TimeUnit.MINUTES);
            System.out.println("该新订单信息已放入司机临时队列:"+JSON.toJSONString(newOrderDataVo));
        });
    }

    //获取乘客新订单
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        List<NewOrderDataVo> list = new ArrayList<>();
        //在上面的功能代码已经将乘客的订单存入到redis的list中了，根据id获取值
        //key是司机的id
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST+driverId;

        //判断是否有值，有的话才取出来
        Long size = redisTemplate.opsForList().size(key);
        System.out.println("size:"+size);
        if(size>0){
            for (int i = 0; i < size; i++) {
                //list实现栈的效果
                //取出来的是乘客的订单(已经将对象转换成json格式了)
                String order = (String) redisTemplate.opsForList().leftPop(key);
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(order, NewOrderDataVo.class);
                list.add(newOrderDataVo);
            }
        }
        return list;
    }
    //清空新订单队列数据
    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        //获取司机的key，直接删除redis的数据
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST+driverId;
        //直接删除，司机开启服务后，有新订单会自动创建容器
        redisTemplate.delete(key);
        return true;
    }
}
